/**
 * 	修改时间: 2018年6月22日 上午10:41:21
 * 	以framework-resouce中为基准
 * 
 *	跨iframe方法调用.通过  window.EventBridge.xx的方式调用
 *	先绑定: bind/bindOnece(name,callback)
 *	后触发: trigger(name,[...])
 *	在父窗口中绑定    bindOnWindow/bindOnTop/bindOnParent(window.parent,name,callback)
 * 	经测试:	IE下也能正常处理
 */

;(function() {
	var frameCall=window.top.frameCall;
	if(!frameCall){
		frameCall={};
		window.top.frameCall=frameCall;	//具体结构{window:{name:[数组]}} 数组中
	}
	function guid(){
	    return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
	        var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8);
	        return v.toString(16);
	    });
	}
	/**
	 * 复制数组,必须要复制,防止进行trigger时,如果回调中进行删除回调,则造成循环遍历无法遍历完的问题
	 */
	function clone(array){
		var n=[];
		if(!array)return n;
		for(var i=0;i<array.length;i++){
			n.push(array[i]);
		}
		return n;
	}
	/**
	 *	结构中: 
	 * @param {Object} wd
	 */
	function CallItem(wd){
		this.wd=wd;
		this.callsMap={};	//{name:[]}数组中保存的是回调方法


		/**
		 * 获取指定名称的回调数组
		 */
		this.getCalls=function(name){
			var calls=this.callsMap[name];
			if(!calls){
				calls=[];
				this.callsMap[name]=calls;
			}
			return calls;
		};
		/**
		 * 是否有指定名称的回调
		 * callback可以为空
		 */
		this.hasCall=function(name,callback){
			var calls=this.callsMap[name];
			if(callback){
				if(calls&&calls.length>0){
					for(var i=0;i<calls.length;i++){
						if(calls[i]==callback)return true;
					}
				}
				return false;
			}
			else{
				return calls&&calls.length>0;
			}
		};
		this.add=function(name,callback){
			var calls=this.getCalls(name);
			calls.push(callback);
		};
		/**
		 * @param name		表示事件名称.必须非空
		 * @param callback	表示限定的回调函数.可以为空
		 *
		 */
		this.del=function(name,callback){
			var calls=this.getCalls(name);

			if(callback){
				var index=-1;
				for(var i=0;i<calls.length;i++){
					if(calls[i]==callback){
						index=i;
						break;
					}
				}
				if(index>-1)calls.splice(index,1);
			}
			else{
				calls.splice(0,calls.length);
			}
		};
		/**
		 * 删除所有注册的方法
		 */
		this.delAll=function(){
			this.callsMap={};
		};
		/**
		 * 触发事件
		 * @param ctx		表示回调时的this对象
		 */
		this.trigger=function(ctx,name){
			var calls=clone(this.getCalls(name));
			var args=Array.prototype.slice.call(arguments,2);
			for(var i=0;i<calls.length;i++){
				var call=calls[i];
				try{
					call.apply(ctx,args);
				}catch(e){
					console.error("EventBridge Trigger发生错误:"+e);
					console.error("调用信息:EventID="+this.wd+",事件名:"+name);
				}
				
			}
		};
		/**
		 * 调用一组事件
		 * @param ctx		表示回调时的this对象
		 */
		this.call=function(ctx,name){
			var calls=clone(this.getCalls(name));
			var args=Array.prototype.slice.call(arguments,2);
			var re=[];
			for(var i=0;i<calls.length;i++){
				var call=calls[i];
				try{
					re.push(call.apply(ctx,args));
				}catch(e){
					console.error("EventBridge Call发生错误:"+e);
					console.error("调用信息:EventID="+this.wd+",事件名:"+name);
				}
			}
			return re;
		};
	};
	/**
	 * 构建调用时的参数
	 */
	function buildArgs(ctx,args,sindex){
		var params= Array.prototype.slice.call(args,sindex||0);
		params.unshift(ctx);
		return params;
	}
	
	var currentWd=window.EventID||guid();	//使用原来的或者生成
	var eventBridge={
		onLoad:function(wd){
			var item=frameCall[wd];
			if(!item){
				frameCall[wd]=new CallItem(wd);
			}
		},
		onUnload:function(wd){
			delete frameCall[wd];
		},
		/**
		 * 是否绑定指定名称的回调.
		 * wind表示限定的窗口.
		 * callback可能为空
		 */
		hasBind:function(name,wind,callback){
			if(typeof(wind)=="function")callback=wind;
			for(var wd in frameCall){
				if(wind&&wind.EventID!=wd)continue;
				var item=frameCall[wd];
				if(item.hasCall(name,callback))return true;
			}
			return false;
		},
		/**
		 * .返回原始callback,可用于再次绑定或者解绑等
		 */
		bind:function(name,callback){		//绑定到当前窗口下
			var item=frameCall[currentWd];
			if(!item){
				item=new CallItem(currentWd);
				frameCall[currentWd]=item;
			}
			item.add(name,callback);
			return callback;
		},
		/**
		 * 仅执行一次的回调.返回原始callback,可用于再次绑定或者解绑等
		 * @param {Object} name
		 * @param {Object} callback		返回false则不会移除此回调
		 */
		bindOnce:function(name,callback){
			var t=this;
			var cb=function(){	//调用原来的函数
				var re=callback.apply(this,Array.prototype.slice.call(arguments));
				if(re!==false)t.unbind(name,cb);	//如果返回值为false则不会移除.其他返回或无返回都不会移除
			}
			this.bind(name,cb);
			return callback;
		},
		/**
		 * 解绑所有窗口的回调
		 * @param {Object} name			必须限定
		 * @param {Object} callback		可以为空
		 */
		unbind:function(name,callback){
			for(var wd in frameCall){
				var item=frameCall[wd];
				item.del(name,callback);
			}
		},
		/**
		 * 解绑所有窗口的所有回调
		 */
		unbindAll:function(){
			for(var wd in frameCall){
				delete frameCall[wd];
			}
		},
		/**
		 * 异步触发方法执行, js中未单线程,所以无同异步区分.与call仅,一个有返回值,一个无
		 * 如果首个参数:为数值,则进行延迟调用delay是非必须参数
		 */
		trigger:function(delay,name){
			var args=arguments;
			if(typeof(delay)=="number"){	//延迟调用
				setTimeout(function(){
					for(var wd in frameCall){
						var item=frameCall[wd];
						item.trigger.apply(item,buildArgs(item,args,1));
					}
				},delay);
			}else{
				for(var wd in frameCall){
					var item=frameCall[wd];
					item.trigger.apply(item,buildArgs(item,args));
				}
			}
			
		},
		/**
		 * 同步触发,调用,有返回值 js中未单线程,所以无同异步区分.与trigger仅,一个有返回值,一个无
		 */
		call:function(name){
			var ret=null;
			for(var wd in frameCall){
				var item=frameCall[wd];
				var rs=item.call.apply(item,buildArgs(item,arguments));
				for(var i=0;i<rs.length;i++){
					ret=BaseUtil.checkDefault(rs[i],ret);
				}
			}
			return ret;
		},
		/**
		 * 在指定window对象上绑定事件.相当于在指定window执行方法一样.使用额变量都是指定wind窗口中的  .
		 * @param {Object} wind			window对象
		 * @param {Object} name
		 * @param {Object} callback
		 */
		bindOnWindow:function(wind,name,callback){
			var item=frameCall[wind.EventID];
			if(!item){
				item=new CallItem(wind.EventID);
				frameCall[wind.EventID]=item;
			}
			var funStr=callback.toString();
			var cb=wind.buildFunction(funStr);	//必须交由具体的win进行编译,否则没有在指定窗口运行的功能
			item.add(name,cb);
			return cb;
		},
		/**
		 * 在window.top中绑定方法.      .
		 * @param {Object} name
		 * @param {Object} callback
		 */
		bindOnTop:function(name,callback){
			return this.bindOnWindow(window.top,name,callback);
		},
		/**
		 * 在window.parent中绑定方法.      .
		 */
		bindOnParent:function(name,callback){
			return this.bindOnWindow(window.parent,name,callback);
		},
		/**
		 * 在指定的window中运行指定的方法.并且返回值.调用时后面的参数将会作为函数调用的参数. .
		 */
		runOnWindow:function(wind,callback){
			var funStr=callback.toString();
			var cb=wind.buildFunction(funStr);	//必须交由具体的win进行编译,否则没有在指定窗口运行的功能			
			return cb.apply(wind,Array.prototype.slice.call(arguments,2));
		},
		/**
		 * 在top中执行
		 */
		runOnTop:function(callback){
			var args=Array.prototype.slice.call(arguments);
			args.unshift(window.top);
			return this.runOnWindow.apply(this,args);
		},
		/**
		 * 在parent中执行
		 */
		runOnParent:function(callback){
			var args=Array.prototype.slice.call(arguments);
			args.unshift(window.parent);
			return this.runOnWindow.apply(this,args);
		},
		/**
		 * 获取当前窗口的eventID
		 */
		getCurrentEventID:function(){
			return currentWd;
		},
		/**
		 * 生成一个随机的key
		 */
		getRandomKey:function(){
			return guid();
		}
	};

	/* 不进行注册.避免值源浪费
	eventBridge.onLoad(currentWd);
	*/
	/*
	window.addEventListener("load",function(){
		eventBridge.onLoad(window);
	});
	*/
	if(window){

		if(window.addEventListener){
			window.addEventListener("unload",function(){
				eventBridge.onUnload(currentWd);
			});
		}
		else if(window.attachEvent){
			window.attachEvent("onunload",function(){
				eventBridge.onUnload(currentWd);
			});
		}
		window.EventID=currentWd;
		window.EventBridge=eventBridge;
		
		//必须每一级window都定义指定的buildFunction方法
		window.buildFunction=function(funStr){
			//截取方法体
			var funBody= funStr.substring(funStr.indexOf("{")+1,funStr.lastIndexOf("}"))||"";
			var starti=funStr.indexOf("(");
			var argsStr=funStr.substring(starti+1,funStr.indexOf(")",starti));
			var args=[];
			var pnames=argsStr.split(",");
			for(var i=0;i<pnames.length;i++){
				var pname=(pnames[i]||"").replace(/^\s+|\s+$/gm,'');
				if(pname){
					args.push(pname);
				}
			}
			args.push(funBody.replace(/^\s+|\s+$/gm,''));
			return Function.apply(Function,args);
		}
	}
})();





